﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;

namespace DatabaseViewer.Domain
{
    public class CustomTable : ICustomTypeDescriptor
    {
        private string tableName;
        private PropertyDescriptorCollection _properties;
        private void AddAttribute(string tableName)
        {
            TypeDescriptor.AddAttributes(this, new Attribute[] 
                                    {
                                        new System.Data.Linq.Mapping.DatabaseAttribute() { Name = tableName }
                                    });
        }

        public CustomTable(string name)
        {
            tableName = name;
            AddAttribute(name);
        }

        internal void AddColumn(System.Data.Linq.Mapping.ColumnAttribute column)
        {
            var p = new FieldPropertyDescriptor(new CustomFieldInfo(column) { });

            if (_properties == null)
                _properties = new PropertyDescriptorCollection(new PropertyDescriptor[] { p });
            else
                _properties.Add(p);
        }
        internal void AddAssociation(string name)
        {
            var props = this.GetProperties();
            FieldPropertyDescriptor prop = props.Find(name, true) as FieldPropertyDescriptor;
            if (prop != null)
            {
               prop.AddAttribute(new System.Data.Linq.Mapping.AssociationAttribute() { Name = name});
            }
        }

        public AttributeCollection GetAttributes()
        {
            return new AttributeCollection(new System.Data.Linq.Mapping.DatabaseAttribute() { Name = tableName });            
        }

        public string GetClassName()
        {
            return tableName;
        }

        public string GetComponentName()
        {
            return null;
        }

        public TypeConverter GetConverter()
        {
            return null;
        }

        public EventDescriptor GetDefaultEvent()
        {
            return null;
        }

        public PropertyDescriptor GetDefaultProperty()
        {
            return GetProperties()[0];
        }

        public object GetEditor(Type editorBaseType)
        {
            return null;
        }

        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return null;
        }

        public EventDescriptorCollection GetEvents()
        {
            return null;
        }

        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            return GetProperties();
        }

        public PropertyDescriptorCollection GetProperties()
        {
            throw new NotImplementedException();
        }

        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }
    }

    public class CustomFieldInfo : FieldInfo
    {
        private System.Data.Linq.Mapping.ColumnAttribute _column;
        public CustomFieldInfo(System.Data.Linq.Mapping.ColumnAttribute column)
            : base()
        {
            _column = column;
        }
    }

    public class FieldPropertyDescriptor : PropertyDescriptor
    {
        private FieldInfo _field;

        public FieldPropertyDescriptor(FieldInfo field)
            : base(field.Name,
                (Attribute[])field.GetCustomAttributes(typeof(Attribute), true))
        {
            _field = field;
           
        }

        public FieldInfo Field { get { return _field; } }

        public override bool Equals(object obj)
        {
            FieldPropertyDescriptor other = obj as FieldPropertyDescriptor;
            return other != null && other._field.Equals(_field);
        }

        public override int GetHashCode() { return _field.GetHashCode(); }

        public override bool IsReadOnly { get { return false; } }

        public override void ResetValue(object component) { }

        public override bool CanResetValue(object component) { return false; }

        public override bool ShouldSerializeValue(object component)
        {
            return true;
        }

        public override Type ComponentType
        {
            get { return _field.DeclaringType; }
        }

        public override Type PropertyType { get { return _field.FieldType; } }

        public override object GetValue(object component)
        {
            return _field.GetValue(component);
        }

        public void AddAttribute(Attribute a)
        {
            var l = new List<Attribute>( AttributeArray);
            l.Add(a);
            AttributeArray = l.ToArray();
        }

        public override void SetValue(object component, object value)
        {
            _field.SetValue(component, value);
            OnValueChanged(component, EventArgs.Empty);
        }
    }

}
